﻿using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.TeamFoundation.WorkItemTracking.Client;


namespace Qetza.TeamFoundation.WorkItemQuery.Admin
{
    /// <summary>
    /// Provides extension methods for the <see cref="QueryFolder"/> class.
    /// </summary>
    public static class QueryFolderExtensions
    {
        #region Methods

        /// <summary>
        /// Creates the folders for the specified path.
        /// </summary>
        /// <param name="source">
        /// The <see cref="QueryFolder"/> to invoke the find function on.
        /// </param>
        /// <param name="folderPath">
        /// The folder path to create.
        /// </param>
        /// <returns>
        /// The <see cref="QueryFolder"/> at the specified path.
        /// </returns>
        public static QueryFolder CreateFolder(this QueryFolder source, string folderPath)
        {
            // validate parameters
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            if (folderPath == null)
            {
                throw new ArgumentNullException("folderPath");
            }

            // search recursively on path
            if (folderPath.Length == 0)
            {
                return source;
            }

            return CreateFolder(source, folderPath.Split(new[] { '/' }), 0);
        }

        /// <summary>
        /// Retrieves the <see cref="QueryItem"/> in the <see cref="QueryFolder"/> at the specified value path.
        /// </summary>
        /// <param name="source">
        /// The <see cref="QueryFolder"/> to invoke the find function on.
        /// </param>
        /// <param name="valuePath">
        /// The value path of an item.
        /// </param>
        /// <returns>
        /// The <see cref="QueryItem"/> at the specified value path if found; otherwise a null reference.
        /// </returns>
        public static QueryItem Find(this QueryFolder source, string valuePath)
        {
            // validate parameters
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            if (valuePath == null)
            {
                throw new ArgumentNullException("valuePath");
            }

            // search recursively on path
            return Find(source, valuePath.Split(new[] { '/' }), 0);
        }

        #endregion

        #region Private Helpers

        // Creates the folders for the specified path.
        private static QueryFolder CreateFolder(QueryFolder source, string[] path, int pos)
        {
            foreach (var item in source)
            {
                if (string.Compare(item.Name, path[pos], true) == 0)
                {
                    // check type
                    if (!(item is QueryFolder))
                    {
                        throw new InvalidParameterException(string.Format(ResourceStrings.ErrorInvalidPath, path[pos]));
                    }

                    if (pos == path.Length - 1)
                    {
                        // last item in path, already exists
                        return (QueryFolder)item;
                    }

                    // create sub folders
                    return CreateFolder((QueryFolder)item, path, pos + 1);
                }
            }

            // folder not found, create folder
            var folder = source;
            for (var i = pos; i < path.Length; ++i)
            {
                folder = new QueryFolder(path[i], folder);
            }

            return folder;
        }

        // Retrieves the QueryItem at the specified value path.
        private static QueryItem Find(QueryFolder source, string[] path, int pos)
        {
            foreach (var item in source)
            {
                if (string.Compare(item.Name, path[pos], true) == 0)
                {
                    if (pos == path.Length - 1)
                    {
                        // last item in path, found item
                        return item;
                    }

                    if (item is QueryFolder)
                    {
                        // folder, continue search
                        return Find((QueryFolder)item, path, pos + 1);
                    }

                    // invalid path, item is not a folder
                    return null;
                }
            }

            // item not found
            return null;
        }

        #endregion
    }
}
